#ifndef __QE_SDHCI_H__
#define __QE_SDHCI_H__



#include "qe_mmc.h"


enum {
    SDHCI_REG_DMA_ADDRESS               = 0x00,
    SDHCI_REG_BLOCK_SIZE                = 0x04,
    SDHCI_REG_BLOCK_COUNT               = 0x06,
    SDHCI_REG_ARGUMENT                  = 0x08,
    SDHCI_REG_TRANSFER_MODE             = 0x0C,
    SDHCI_REG_COMMAND                   = 0x0E,
    SDHCI_REG_RESPONSE                  = 0x10,
    SDHCI_REG_RESP1                     = 0x14,
    SDHCI_REG_RESP2                     = 0x18,
    SDHCI_REG_RESP3                     = 0x1C,
    SDHCI_REG_BUFFER                    = 0x20,
    SDHCI_REG_PRESENT_STATE             = 0x24,
    SDHCI_REG_HOST_CTRL                 = 0x28,
    SDHCI_REG_POWER_CTRL                = 0x29,
    SDHCI_REG_CLOCK_CTRL                = 0x2C,
    SDHCI_REG_TIMEOUT_CTRL              = 0x2E,
    SDHCI_REG_RESET                     = 0x2F,
    SDHCI_REG_INT_STATUS                = 0x30,
    SDHCI_REG_ERR_INT_STS               = 0x32,
    SDHCI_REG_INT_ENABLE                = 0x34,
    SDHCI_REG_ERR_INT_STS_EN            = 0x36,
    SDHCI_REG_NOR_SIG_ENABLE            = 0x38,
    SDHCI_REG_ERR_SIG_ENABLE            = 0x3A,
    SDHCI_REG_CAPABILITIES              = 0x40,
    SDHCI_REG_CAPABILITIES_1            = 0x44,
    SDHCI_REG_ADMA_ADDRESS              = 0x58,
    SDHCI_REG_ADMA_ADDRESS_HI           = 0x5C,
    SDHCI_REG_VERSION                   = 0xFE
};

/* Block size */
#define SDHCI_MAKE_BLKSZ(dma, blksz)    (((dma & 0x7) << 12) | (blksz & 0xFFF))

#define SDHCI_RESET_DATA                QE_BIT(2)
#define SDHCI_RESET_CMD                 QE_BIT(1)
#define SDHCI_RESET_ALL                 QE_BIT(0)

/* Host control */
#define SDHCI_CTRL_LED		            QE_BIT(0)
#define SDHCI_CTRL_4BITBUS	            QE_BIT(1)
#define SDHCI_CTRL_HISPD	            QE_BIT(2)
#define SDHCI_CTRL_DMA_MASK	            0x18
#define SDHCI_CTRL_SDMA	                0x00
#define SDHCI_CTRL_ADMA1	            0x08
#define SDHCI_CTRL_ADMA32	            0x10
#define SDHCI_CTRL_ADMA64	            0x18
#define SDHCI_CTRL_8BITBUS	            QE_BIT(5)
#define SDHCI_CTRL_CD_TEST_INS	        QE_BIT(6)
#define SDHCI_CTRL_CD_TEST	            QE_BIT(7)

/* Capabilities */
#define SDHCI_CAP_SLOT_TYPE             0xC0000000
#define SDHCI_CAP_EMB_SLOT              0x40000000
#define SDHCI_CAP_64BIT                 QE_BIT(28)
#define SDHCI_CAP_VDD_180               QE_BIT(26)
#define SDHCI_CAP_VDD_300               QE_BIT(25)
#define SDHCI_CAP_VDD_330               QE_BIT(24)
#define SDHCI_CAP_SDMA                  QE_BIT(22)
#define SDHCI_CAP_HISPD                 QE_BIT(21)
#define SDHCI_CAP_ADMA1                 QE_BIT(20)
#define SDHCI_CAP_ADMA2                 QE_BIT(19)
#define SDHCI_CAP_8BIT                  QE_BIT(18)

/* Caps1 */
#define SDHCI_CAP_SDR50	                0x00000001
#define SDHCI_CAP_SDR104	            0x00000002
#define SDHCI_CAP_DDR50 	            0x00000004
#define SDHCI_CAP_SDR50_TUNING	        0x00002000

#define SDHCI_CLOCK_MUL_MASK	        0x00FF0000
#define SDHCI_CLOCK_MUL_SHIFT           16

#define SDHCI_CLOCK_BASE_MASK	        0x00003F00
#define SDHCI_CLOCK_V3_BASE_MASK	    0x0000FF00
#define SDHCI_CLOCK_BASE_SHIFT	        8

#define SDHCI_MAX_DIV_SPEC_200	        256
#define SDHCI_MAX_DIV_SPEC_300	        2046

#define SDHCI_QUIRK_NO_1_8_V		    QE_BIT(9)
#define SDHCI_QUIRK_USE_WIDE8		    QE_BIT(8)
#define SDHCI_QUIRK_WAIT_SEND_CMD	    QE_BIT(6)
#define SDHCI_QUIRK_BROKEN_HISPD_MODE	QE_BIT(5)
#define SDHCI_QUIRK_BROKEN_VOLTAGE	    QE_BIT(4)
#define SDHCI_QUIRK_NO_HISPD_BIT	    QE_BIT(3)
#define SDHCI_QUIRK_BROKEN_R1B		    QE_BIT(2)
#define SDHCI_QUIRK_REG32_RW		    QE_BIT(1)
#define SDHCI_QUIRK_32BIT_DMA_ADDR	    QE_BIT(0)

/*
 * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
 */
#define SDHCI_DEFAULT_BOUNDARY_SIZE	    (512 * 1024)
#define SDHCI_DEFAULT_BOUNDARY_ARG	    (7)

#define SDHCI_HOST_VERSION	            0xFE
#define SDHCI_VENDOR_VER_MASK	        0xFF00
#define SDHCI_VENDOR_VER_SHIFT	        8
#define SDHCI_SPEC_VER_MASK	            0x00FF
#define SDHCI_SPEC_VER_SHIFT            0
#define SDHCI_SPEC_100                  0
#define SDHCI_SPEC_200                  1
#define SDHCI_SPEC_300                  2

#define SDHCI_ADMA_MAX_LEN              (65532)
#define SDHCI_ADMA_DESC_LEN             (8)
#define SDHCI_ADMA_TAB_NO_ENTRIES       (256 * QE_MMC_MAX_BLOCK_LEN) / SDHCI_ADMA_MAX_LEN
#define SDHCI_ADMA_TAB_SIZE             (SDHCI_ADMA_TAB_NO_ENTRIES * SDHCI_ADMA_DESC_LEN)

/* Powr */
#define SDHCI_POWER_ON		            0x01
#define SDHCI_POWER_180	                0x0A
#define SDHCI_POWER_300	                0x0C
#define SDHCI_POWER_330	                0x0E
#define SDHCI_POWER_EMMC_HW_RST         0x10

/* Interrupt */
#define SDHCI_INT_RESPONSE	            QE_BIT(0)
#define SDHCI_INT_DATA_END	            QE_BIT(1)
#define SDHCI_INT_DMA_END	            QE_BIT(3)
#define SDHCI_INT_SPACE_AVAIL	        QE_BIT(4)
#define SDHCI_INT_DATA_AVAIL	        QE_BIT(5)
#define SDHCI_INT_CARD_INSERT	        QE_BIT(6)
#define SDHCI_INT_CARD_REMOVE	        QE_BIT(7)
#define SDHCI_INT_CARD_INT	            QE_BIT(8)
#define SDHCI_INT_ERROR	                QE_BIT(15)
#define SDHCI_INT_TIMEOUT	            QE_BIT(16)
#define SDHCI_INT_CRC		            QE_BIT(17)
#define SDHCI_INT_END_BIT	            QE_BIT(18)
#define SDHCI_INT_INDEX	                QE_BIT(19)
#define SDHCI_INT_DATA_TIMEOUT	        QE_BIT(20)
#define SDHCI_INT_DATA_CRC	            QE_BIT(21)
#define SDHCI_INT_DATA_END_BIT	        QE_BIT(22)
#define SDHCI_INT_BUS_POWER	            QE_BIT(23)
#define SDHCI_INT_ACMD12ERR	            QE_BIT(24)
#define SDHCI_INT_ADMA_ERROR	        QE_BIT(25)

#define SDHCI_INT_NORMAL_MASK	        0x00007FFF
#define SDHCI_INT_ERROR_MASK	        0xFFFF8000

#define SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
#define SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
#define SDHCI_INT_ALL_MASK	((unsigned int)-1)

#define SDHCI_ERR_INT_ALL_MASK          0x0000F3FF

#define SDHCI_CMD_MAX_TIMEOUT			3200
#define SDHCI_CMD_DEFAULT_TIMEOUT		100
#define SDHCI_READ_STATUS_TIMEOUT		1000

/* Present state */
#define SDHCI_CMD_INHIBIT	            QE_BIT(0)
#define SDHCI_DATA_INHIBIT	            QE_BIT(1)
#define SDHCI_DOING_WRITE	            QE_BIT(8)
#define SDHCI_DOING_READ	            QE_BIT(9)
#define SDHCI_SPACE_AVAILABLE	        QE_BIT(10)
#define SDHCI_DATA_AVAILABLE	        QE_BIT(11)
#define SDHCI_CARD_PRESENT	            QE_BIT(16)
#define SDHCI_CARD_STATE_STABLE	        QE_BIT(17)
#define SDHCI_CARD_DETECT_PIN_LEVEL	    QE_BIT(18)
#define SDHCI_WRITE_PROTECT	            QE_BIT(19)

/* Command */
#define SDHCI_CMD_RESP_MASK	            0x03
#define SDHCI_CMD_CRC		            0x08
#define SDHCI_CMD_INDEX	                0x10
#define SDHCI_CMD_DATA		            0x20
#define SDHCI_CMD_ABORTCMD	            0xC0
#define SDHCI_CMD_RESP_NONE	            0x00
#define SDHCI_CMD_RESP_LONG	            0x01
#define SDHCI_CMD_RESP_SHORT	        0x02
#define SDHCI_CMD_RESP_SHORT_BUSY       0x03

#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f)

/* Transfer mode */
#define SDHCI_TRNS_DMA		            QE_BIT(0)
#define SDHCI_TRNS_BLK_CNT_EN	        QE_BIT(1)
#define SDHCI_TRNS_ACMD12	            QE_BIT(2)
#define SDHCI_TRNS_READ	                QE_BIT(4)
#define SDHCI_TRNS_MULTI	            QE_BIT(5)

#define SDHCI_DAT_PRESENT_SEL           QE_BIT(5)

/* Decriptor table defines */
#define SDHCI_ADMA_DESC_ATTR_VALID		QE_BIT(0)
#define SDHCI_ADMA_DESC_ATTR_END		QE_BIT(1)
#define SDHCI_ADMA_DESC_ATTR_INT		QE_BIT(2)
#define SDHCI_ADMA_DESC_ATTR_ACT1		QE_BIT(4)
#define SDHCI_ADMA_DESC_ATTR_ACT2		QE_BIT(5)
#define SDHCI_ADMA_DESC_TRANSFER_DATA   SDHCI_ADMA_DESC_ATTR_ACT2
#define SDHCI_ADMA_DESC_LINK_DESC	    (SDHCI_ADMA_DESC_ATTR_ACT1 | SDHCI_ADMA_DESC_ATTR_ACT2)


/* Clock control */
#define SDHCI_DIVIDER_SHIFT	                8
#define SDHCI_DIVIDER_HI_SHIFT	            6
#define SDHCI_CC_DIV_MASK	                0xFF
#define SDHCI_CC_SDCLK_FREQ_SEL_MASK        0x0000FF00
#define SDHCI_CC_SDCLK_FREQ_SEL_EXT_MASK    0x000000C0
#define SDHCI_DIV_MASK_LEN	                8
#define SDHCI_DIV_HI_MASK	                0x300
#define SDHCI_PROG_CLOCK_MODE               QE_BIT(5)
#define SDHCI_CLOCK_CARD_EN	                QE_BIT(2)
#define SDHCI_CLOCK_INT_STABLE	            QE_BIT(1)
#define SDHCI_CLOCK_INT_EN	                QE_BIT(0)
#define SDHCI_CLK_400_KHZ                   QE_BIT(22)
#define SDHCI_CLK_50_MHZ                    50000000U
#define SDHCI_CLK_52_MHZ                    52000000U
#define SDHCI_CC_MAX_DIV_CNT			    256U
#define SDHCI_CC_EXT_MAX_DIV_CNT            2046

/* Present State */
#define SDHCI_PS_CARD_INSRT                 0x00010000      /* Card inserted */

struct qe_sdhci_host_controller;
typedef struct qe_sdhci_host_controller qe_sdhci_host;

typedef struct 
{
    qe_u8 attr;
    qe_u8 reserved;
    qe_u16 len;
    qe_u32 addr_lo;
} qe_packed qe_sdhci_adma_desc;

typedef struct 
{
    qe_u32 (*read_l)(qe_sdhci_host *host, qe_uint reg);
    qe_u16 (*read_w)(qe_sdhci_host *host, qe_uint reg);
    qe_u8  (*read_b)(qe_sdhci_host *host, qe_uint reg);
    void   (*write_l)(qe_sdhci_host *host, qe_uint reg, qe_u32 val);
    void   (*write_w)(qe_sdhci_host *host, qe_uint reg, qe_u16 val);
    void   (*write_b)(qe_sdhci_host *host, qe_uint reg, qe_u8 val);

    qe_int (*get_cd)(qe_sdhci_host *host);
    void   (*set_control_reg)(qe_sdhci_host *host);
    void   (*set_delay)(qe_sdhci_host *host);
    qe_ret (*set_ios_post)(qe_sdhci_host *host);
    qe_ret (*set_clock)(qe_sdhci_host *host, qe_u32 div);  
} qe_sdhci_ops;

typedef struct qe_sdhci_host_controller
{
    qe_mmc *mmc;
    const qe_sdhci_ops *ops;

    qe_ubase ioaddr;
    qe_ubase start_addr;
    qe_ubase adma_addr;

    qe_ptr aligned_buffer;
    qe_ptr priv;

    qe_uint quirks;
    qe_uint host_caps;
    qe_uint version;
    qe_uint max_clk;
    qe_uint clk_mul;
    qe_uint clock;
    qe_uint bus_width;
    qe_uint voltages;

    qe_u32 flags;
#define SDHCI_USE_SDMA      (1 << 0)
#define SDHCI_USE_ADMA      (1 << 1)
#define SDHCI_USE_ADMA64    (1 << 2)
#define SDHCI_USE_DMA       (SDHCI_USE_SDMA | SDHCI_USE_ADMA | SDHCI_USE_ADMA64)

    qe_sdhci_adma_desc *adma_desc_tab;
    qe_uint desc_slot;

} qe_sdhci_host;



qe_ret 
qe_sdhci_probe(qe_sdhci_host *host, qe_const_str name, const qe_sdhci_ops *ops, qe_ptr priv);

qe_ret
qe_sdhci_setup_cfg(qe_sdhci_host *host, qe_mmc_config *cfg, qe_u32 f_max, qe_u32 f_min);



#endif /* __QE_SDHCI_H__ */
